#!/usr/bin/env python3.10
# -*- encoding: utf-8 -*-
"""
@File    :   controllers.py
@Time    :   2024/01/30 15:59:29
@Author  :   windstarry 
@Version :   1.0
"""
# here put the import lib
from django.contrib.auth import get_user_model
from django.db import transaction
from ninja_extra import api_controller, route, status
from ninja_extra.permissions import IsAuthenticated
from ninja_extra.pagination import (
    PageNumberPaginationExtra,
    PaginatedResponseSchema,
    paginate,
)
from ninja_jwt.authentication import JWTAuth
from ninja_extra.shortcuts import get_object_or_exception


from .mixins import BookViewMixin, StoreViewMixin, StoryBookQuerySetMixin
from .models import Store, StoreBook, StoreBookSubscription
from .schema import (
    IdSchema,
    OKSchema,
    BookSchema,
    CreateBookSchema,
    StoreCreateSchema,
    StoreUpdateSchema,
    StoreMessage,
    StoreRetrieveSchema,
    StoreBookSchema,
    BorrowOrReturnStoreBookSchema,
    StoreBookSubscriptionSerializer,
)

User = get_user_model()


@api_controller("/books", tags=["书籍管理"], permissions=[IsAuthenticated], auth=JWTAuth())
class BooksController(BookViewMixin):
    @route.get(
        "/list",
        response=PageNumberPaginationExtra.get_response_schema(BookSchema),
        summary="书籍列表",
        url_name="book-list",
    )
    @paginate(PageNumberPaginationExtra,page_size=10)
    def list_books(self):
        return self.get_queryset()

    @route.get(
        "/info/{book_id}", response=BookSchema, summary="书籍信息", url_name="book-info"
    )
    def get_book_info(self, book_id: int):
        book = self.get_object_or_exception(
            self.get_queryset(),
            id=book_id,
            error_message="书籍不存在",
        )
        return book


@api_controller("/stores", tags=["仓库管理"], permissions=[IsAuthenticated], auth=JWTAuth())
class StoresController(StoreViewMixin):
    @route.get(
        "",
        response=PageNumberPaginationExtra.get_response_schema(StoreRetrieveSchema),
        summary="仓库列表",
        url_name="store-list",
    )
    @paginate(PageNumberPaginationExtra)
    def list_stores(self):
        return self.get_queryset()

    @route.post(
        "",
        response=[(201, IdSchema), (400, OKSchema)],
        summary="创建仓库",
        url_name="create-store",
    )
    def create_store(self, store: StoreCreateSchema):
        try:
            store = store.create_store(owner=self.context.request.user)
            return 201, dict(id=store.pk)
        except Exception as ex:
            return 400, dict(details=str(ex))

    @route.get(
        "/{store_id}",
        response=StoreRetrieveSchema,
        summary="仓库详情",
        url_name="store-detail",
    )
    def retrieve_store(self, store_id: int):
        store = self.get_object_or_exception(
            self.get_queryset(),
            id=store_id,
            error_message="仓库不存在",
        )
        return store

    @route.delete(
        "/{store_id}", response={204: dict}, summary="删除仓库", url_name="store-delete"
    )
    def delete_store(self, store_id: int):
        store = self.get_object_or_exception(
            self.get_queryset(),
            id=store_id,
            error_message="仓库不存在",
        )
        store.delete()
        return self.create_response("仓库已删除", status_code=status.HTTP_204_NO_CONTENT)

    @route.generic(
        "/{store_id}",
        methods=["PUT"],
        response=StoreRetrieveSchema,
        summary="修改仓库",
        url_name="update",
    )
    def update_store(self, store_id: int, store_schema: StoreUpdateSchema):
        store = self.get_object_or_exception(
            self.get_queryset(), id__exact=store_id, error_message="仓库不存在"
        )
        # 增加modifier
        store.modifier = self.context.request.user.username
        store_schema.update(store)
        return store


@api_controller(
    "/stores/{store_id}", tags=["仓库书籍管理"], permissions=[IsAuthenticated], auth=JWTAuth()
)
class StoreBookController(StoreViewMixin):
    User = get_user_model()
    base_url = ""

    @route.get(
        "/books",
        response=PaginatedResponseSchema[StoreBookSchema],
        summary="书籍列表",
        url_name="books",
    )
    @paginate(PageNumberPaginationExtra)
    def list_store_books(self, store_id: int):
        stores = StoreBook.objects.filter(
            store_id=store_id, store__owner_id=self.context.request.user
        )
        return stores

    @route.post(
        "/book/create",
        response=[(201, BookSchema), (400, OKSchema)],
        summary="新增书籍",
        url_name="book-create",
    )
    def add_store_book(self, store_id: int, book: CreateBookSchema):
        try:
            store = self.get_object_or_exception(
                Store,
                id=store_id,
                error_message="仓库不存在",
            )
            book = book.save(created_by=self.context.request.user)
            StoreBook.objects.create(book=book, store=store)
            return 201, book
        except Exception as ex:
            return self.create_response(
                str(ex), status_code=status.HTTP_400_BAD_REQUEST
            )

    def get_object(self, store_id: int, book_id: int):
        store_book = self.get_object_or_none(
            StoreBook.objects.select_related("store", "book"),
            store__id=store_id,
            book__id=book_id,
            store__owner_id=self.context.request.user,
        )
        return store_book

    @route.post(
        "/book/{book_id}/borrow/{user_id}/",
        response={200: BorrowOrReturnStoreBookSchema, 400: dict},
        summary="书籍借出",
        url_name="book-borrow",
    )
    def borrow_store_books(self, store_id: int, book_id: int, user_id: int):
        store_book = self.get_object(store_id, book_id)

        user = self.get_object_or_exception(
            self.User,
            id=user_id,
            error_message="用户不存在",
        )
        if store_book.borrowed_by:
            return self.create_response(
                message="书籍已借出",
                status_code=status.HTTP_400_BAD_REQUEST,
            )
        store_book.borrowed_by = user
        store_book.save()
        return store_book

    @route.post(
        "/book/{book_id}/return",
        response={200: StoreMessage, 400: StoreMessage},
        summary="书籍归还",
        url_name="book-return",
    )
    def return_store_books(self, store_id: int, book_id: int):
        store_book = self.get_object(store_id, book_id)
        if store_book.borrowed_by:
            store_book.borrowed_by = None
            store_book.save()
            # todo
            # process_subscription_notification(store_book_id=store_book.id)
            return status.HTTP_200_OK, StoreMessage(message="书籍已归还")
        return status.HTTP_400_BAD_REQUEST, StoreMessage(message="书籍已归还")


@api_controller(
    "/books", tags=["书籍订阅管理"], permissions=[IsAuthenticated], auth=JWTAuth()
)
class StoryBookSubscribeController(StoryBookQuerySetMixin):
    @route.post(
        "/{store_book_id}/{user_id}/subscriber",
        response=IdSchema,
        summary="书籍预订",
        url_name="subscribe",
    )
    @transaction.atomic
    def subscribe(self, store_book_id: int, user_id: int):
        user = get_object_or_exception(
            User,
            id=user_id,
            error_message="用户不存在",
        )
        store_book = get_object_or_exception(
            StoreBook,
            id=store_book_id,
            store__owner=self.context.request.user,
            error_message="用户不存在",
        )
        subscription = StoreBookSubscription.objects.create(
            store_book=store_book, subscriber=user
        )
        return dict(id=subscription.pk)

    @route.post(
        "/{store_book_subscription_id}/unsubscribe",
        response={status.HTTP_204_NO_CONTENT: OKSchema},
        summary="取消预订",
        url_name="unsubscribe",
    )
    @transaction.atomic
    def unsubscribe(self, store_book_subscription_id: int):
        instance = get_object_or_exception(
            StoreBookSubscription,
            id=store_book_subscription_id,
            error_message="订阅信息不存在",
        )
        instance.delete()
        return self.create_response("", status_code=status.HTTP_204_NO_CONTENT)

    @route.get(
        "/{store_id}/subscribers",
        response=PaginatedResponseSchema[StoreBookSubscriptionSerializer],
        summary="预订人员列表",
        url_name="subscribers",
    )
    @paginate(PageNumberPaginationExtra)
    def list(self, store_id: int):
        return self.get_queryset().filter(store_book__store_id=store_id)
